From 933159e3b26f2d8aa75f583dd74e76a70e60f401 Mon Sep 17 00:00:00 2001 From: Pedro H S Balbino <30302237+phsb5321@users.noreply.github.com> Date: Sat, 1 Aug 2026 02:07:52 -0300 Subject: [PATCH] ci(sonar): stop a runner backlog from failing an unrelated PR MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `SonarQube standalone scan` is a required check, so when the 10-minute job timeout killed it mid-coverage the PR went red for a reason that had nothing to do with the diff — and the only remedy was a manual re-run once the queue drained. Observed 2026-08-01: a 13-run backlog hit the two self-hosted runners and the job ran 02:23:00 -> 02:33:23 before the limit cancelled it. Runs back to 07-28 were green; nothing about the code changed. All three fixes from #319, because they address different halves of the problem: - concurrency group per ref, cancel-in-progress on pull_request only. Superseded pushes no longer leave scans competing for runners. Pushes to main are not superseded in the same sense, so they are never cancelled. - drop `-race` from the coverage run. `Test (go test -race)` in ci.yml is also a required check and already gates races on every PR; running the detector twice buys no coverage signal and roughly doubles this step. `-covermode=atomic` stays and does not need the race detector. - raise `timeout-minutes` 10 -> 20 as headroom for a genuinely contended run. The step cannot hang indefinitely on a real failure: `|| true` swallows non-zero exits, not wall time. Closes #319 Signed-off-by: Pedro H S Balbino <30302237+phsb5321@users.noreply.github.com> --- .github/workflows/sonar.yml | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/.github/workflows/sonar.yml b/.github/workflows/sonar.yml index d8a50f90..1aaf70bb 100644 --- a/.github/workflows/sonar.yml +++ b/.github/workflows/sonar.yml @@ -7,6 +7,15 @@ on: types: [opened, synchronize, reopened] workflow_dispatch: +# One scan per ref. A superseded push used to leave its scan running, +# and two self-hosted runners shared with ci.yml cannot absorb a 13-run +# backlog — the stale runs starved the live one until it hit the job +# timeout (issue #319). Pushes to main are never superseded in the same +# sense, so only PR runs are cancelled. +concurrency: + group: sonar-${{ github.ref }} + cancel-in-progress: ${{ github.event_name == 'pull_request' }} + # Workflow-level permissions — least-privilege baseline that every job # inherits unless it overrides. zizmor `undocumented-permissions` rule # wants an inline rationale per grant. @@ -23,7 +32,11 @@ jobs: scan: name: SonarQube standalone scan runs-on: [self-hosted, dokku] - timeout-minutes: 10 + # 20, not 10: the coverage run shares two self-hosted runners with + # ci.yml, and a contended run took 10m23s before the old limit killed + # it mid-step (issue #319). The step cannot hang indefinitely on a real + # failure — `|| true` only swallows non-zero exits, not wall time. + timeout-minutes: 20 permissions: contents: read # same rationale as workflow level. pull-requests: read # same rationale as workflow level. @@ -65,7 +78,11 @@ jobs: # (the `|| true` swallows the failure). mkdir -p "$HOME/.wa-test-tmp" export TMPDIR="$HOME/.wa-test-tmp" - go test -race -shuffle=on -coverprofile=cover.out -covermode=atomic ./... || true + # No -race here. ci.yml's `Test (go test -race)` job is the race + # gate and is required on every PR; running the detector a second + # time buys no coverage signal and roughly doubles this step's + # wall time on a contended runner (issue #319). + go test -shuffle=on -coverprofile=cover.out -covermode=atomic ./... || true - name: SonarQube scan if: steps.check.outputs.skip == 'false' uses: SonarSource/sonarqube-scan-action@299e4b793aaa83bf2aba7c9c14bedbb485688ec4 # v7.1.0