From dc2f7b0dd95544cd550de3028f89193576e958b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=2E=20M=C3=BCnker?= <30596615+MueChr@users.noreply.github.com> Date: Fri, 30 Aug 2024 10:37:47 +0200 Subject: [PATCH] Add a polling timeout (#50) The property timeout-minutes in a GitHub step is not supported in composed actions. So the workaround to stop the waiting for finishing the sonar scan is not working in such cases. To fix this issue, a polling timeout variable was introduced, which stops the waiting if the timeout is reached. --- action.yml | 6 ++- script/check-quality-gate.sh | 16 +++++++- test/check-quality-gate-test.bats | 63 ++++++++++++++++++++++++++----- 3 files changed, 74 insertions(+), 11 deletions(-) diff --git a/action.yml b/action.yml index 9b3b9c7..5f932ba 100644 --- a/action.yml +++ b/action.yml @@ -8,13 +8,17 @@ runs: using: "composite" steps: - id: quality-gate-check - run: $GITHUB_ACTION_PATH/script/check-quality-gate.sh ${{ inputs.scanMetadataReportFile }} + run: $GITHUB_ACTION_PATH/script/check-quality-gate.sh "${{ inputs.scanMetadataReportFile }}" "${{ inputs.pollingTimeoutSec }}" shell: bash inputs: scanMetadataReportFile: description: Location of the scanner metadata report file required: false default: .scannerwork/report-task.txt + pollingTimeoutSec: + description: "The maximum time (in seconds) to poll for SonarQube's Quality Gate status. Default: 300." + required: false + default: "300" outputs: quality-gate-status: description: > diff --git a/script/check-quality-gate.sh b/script/check-quality-gate.sh index 925f70b..5ae8c9b 100755 --- a/script/check-quality-gate.sh +++ b/script/check-quality-gate.sh @@ -8,12 +8,19 @@ if [[ -z "${SONAR_TOKEN}" ]]; then fi metadataFile="$1" +pollingTimeoutSec="$2" + if [[ ! -f "$metadataFile" ]]; then echo "$metadataFile does not exist." exit 1 fi +if [[ ! $pollingTimeoutSec =~ ^[0-9]+$ || $pollingTimeoutSec -le 0 ]]; then + echo "'$pollingTimeoutSec' is an invalid value for the polling timeout. Please use a positive, non-zero number." + exit 1 +fi + if [[ ! -z "${SONAR_HOST_URL}" ]]; then serverUrl="${SONAR_HOST_URL%/}" ceTaskUrl="${SONAR_HOST_URL%/}/api$(sed -n 's/^ceTaskUrl=.*api//p' "${metadataFile}")" @@ -37,7 +44,9 @@ fi task="$(curl --location --location-trusted --max-redirs 10 --silent --fail --show-error --user "${SONAR_TOKEN}": "${ceTaskUrl}")" status="$(jq -r '.task.status' <<< "$task")" -until [[ ${status} != "PENDING" && ${status} != "IN_PROGRESS" ]]; do +endTime=$(( ${SECONDS} + ${pollingTimeoutSec} )) + +until [[ ${status} != "PENDING" && ${status} != "IN_PROGRESS" || ${SECONDS} -ge ${endTime} ]]; do printf '.' sleep 5 task="$(curl --location --location-trusted --max-redirs 10 --silent --fail --show-error --user "${SONAR_TOKEN}": "${ceTaskUrl}")" @@ -45,6 +54,11 @@ until [[ ${status} != "PENDING" && ${status} != "IN_PROGRESS" ]]; do done printf '\n' +if [[ ${status} == "PENDING" || ${status} == "IN_PROGRESS" ]] && [[ ${SECONDS} -ge ${endTime} ]]; then + echo "Polling timeout reached for waiting for finishing of the Sonar scan! Aborting the check for SonarQube's Quality Gate." + exit 1 +fi + analysisId="$(jq -r '.task.analysisId' <<< "${task}")" qualityGateUrl="${serverUrl}/api/qualitygates/project_status?analysisId=${analysisId}" qualityGateStatus="$(curl --location --location-trusted --max-redirs 10 --silent --fail --show-error --user "${SONAR_TOKEN}": "${qualityGateUrl}" | jq -r '.projectStatus.status')" diff --git a/test/check-quality-gate-test.bats b/test/check-quality-gate-test.bats index 21af383..49bf4f3 100755 --- a/test/check-quality-gate-test.bats +++ b/test/check-quality-gate-test.bats @@ -38,7 +38,7 @@ teardown() { } export -f curl - run script/check-quality-gate.sh metadata_tmp + run script/check-quality-gate.sh metadata_tmp 300 [ "$status" -eq 0 ] } @@ -52,11 +52,39 @@ teardown() { @test "fail when empty metadata file" { export SONAR_TOKEN="test" - run script/check-quality-gate.sh metadata_tmp + run script/check-quality-gate.sh metadata_tmp 300 [ "$status" -eq 1 ] [ "$output" = "Invalid report metadata file." ] } +@test "fail when no polling timeout is provided" { + export SONAR_TOKEN="test" + run script/check-quality-gate.sh metadata_tmp + [ "$status" -eq 1 ] + [ "$output" = "'' is an invalid value for the polling timeout. Please use a positive, non-zero number." ] +} + +@test "fail when polling timeout is not a number" { + export SONAR_TOKEN="test" + run script/check-quality-gate.sh metadata_tmp metadata_tmp + [ "$status" -eq 1 ] + [ "$output" = "'metadata_tmp' is an invalid value for the polling timeout. Please use a positive, non-zero number." ] +} + +@test "fail when polling timeout is zero" { + export SONAR_TOKEN="test" + run script/check-quality-gate.sh metadata_tmp 0 + [ "$status" -eq 1 ] + [ "$output" = "'0' is an invalid value for the polling timeout. Please use a positive, non-zero number." ] +} + +@test "fail when polling timeout is negative" { + export SONAR_TOKEN="test" + run script/check-quality-gate.sh metadata_tmp -1 + [ "$status" -eq 1 ] + [ "$output" = "'-1' is an invalid value for the polling timeout. Please use a positive, non-zero number." ] +} + @test "fail when no Quality Gate status" { export SONAR_TOKEN="test" echo "serverUrl=http://localhost:9000" >> metadata_tmp @@ -68,7 +96,7 @@ teardown() { } export -f curl - run script/check-quality-gate.sh metadata_tmp + run script/check-quality-gate.sh metadata_tmp 300 read -r github_out_actual < ${GITHUB_OUTPUT} @@ -77,6 +105,23 @@ teardown() { [[ "$output" = *"Quality Gate not set for the project. Please configure the Quality Gate in SonarQube or remove sonarqube-quality-gate action from the workflow."* ]] } +@test "fail when polling timeout is reached" { + export SONAR_TOKEN="test" + echo "serverUrl=http://localhost:9000" >> metadata_tmp + echo "ceTaskUrl=http://localhost:9000/api/ce/task?id=AXlCe3jz9LkwR9Gs0pBY" >> metadata_tmp + + #mock curl + function curl() { + echo '{"task":{"analysisId":"AXlCe3jz9LkwR9Gs0pBY","status":"PENDING"}}' + } + export -f curl + + run script/check-quality-gate.sh metadata_tmp 5 + + [ "$status" -eq 1 ] + [[ "$output" = *"Polling timeout reached for waiting for finishing of the Sonar scan! Aborting the check for SonarQube's Quality Gate."* ]] +} + @test "fail when Quality Gate status WARN" { export SONAR_TOKEN="test" echo "serverUrl=http://localhost:9000" >> metadata_tmp @@ -94,7 +139,7 @@ teardown() { } export -f curl - run script/check-quality-gate.sh metadata_tmp + run script/check-quality-gate.sh metadata_tmp 300 read -r github_out_actual < ${GITHUB_OUTPUT} @@ -121,7 +166,7 @@ teardown() { } export -f curl - run script/check-quality-gate.sh metadata_tmp + run script/check-quality-gate.sh metadata_tmp 300 read -r github_out_actual < ${GITHUB_OUTPUT} @@ -147,7 +192,7 @@ teardown() { } export -f curl - run script/check-quality-gate.sh metadata_tmp + run script/check-quality-gate.sh metadata_tmp 300 read -r github_out_actual < ${GITHUB_OUTPUT} @@ -187,7 +232,7 @@ teardown() { } export -f sleep - run script/check-quality-gate.sh metadata_tmp + run script/check-quality-gate.sh metadata_tmp 300 read -r github_out_actual < ${GITHUB_OUTPUT} @@ -220,7 +265,7 @@ teardown() { export GITHUB_OUTPUT="${github_output_dir}/github_output" touch "${GITHUB_OUTPUT}" - run script/check-quality-gate.sh metadata_tmp + run script/check-quality-gate.sh metadata_tmp 300 read -r github_out_actual < "${GITHUB_OUTPUT}" @@ -246,7 +291,7 @@ teardown() { } export -f curl - run script/check-quality-gate.sh metadata_tmp + run script/check-quality-gate.sh metadata_tmp 300 [ "$status" -eq 0 ] [[ "$output" = *"::set-output name=quality-gate-status::PASSED"* ]]