From 5574ab1fd189a2857f9bb9e1eb5bd6649f032871 Mon Sep 17 00:00:00 2001 From: santidev21 Date: Wed, 30 Sep 2026 21:01:58 -0500 Subject: [PATCH 1/2] ci(sonarcloud): add SonarCloud analysis workflow with Quality Gate on PRs - New .github/workflows/sonarcloud.yml: dotnet-sonarscanner begin/build/ test/end on push to main, pull requests and manual dispatch. - sonar.qualitygate.wait=true on pull_request events only: the Sonar way gate evaluates new code, so a red build means the PR introduced issues. The first push to main is the baseline (everything counts as new) and must not block CI on pre-existing debt. - PR parameters are passed explicitly because the scanner does not auto-detect GitHub Actions. - Job is skipped for Dependabot and fork PRs (no repository secrets). - fetch-depth: 0 so SonarCloud gets blame data for new-code detection. - .sonarqube/ added to .gitignore (scanner working directory). --- .github/workflows/sonarcloud.yml | 105 +++++++++++++++++++++++++++++++ .gitignore | 3 + 2 files changed, 108 insertions(+) create mode 100644 .github/workflows/sonarcloud.yml diff --git a/.github/workflows/sonarcloud.yml b/.github/workflows/sonarcloud.yml new file mode 100644 index 0000000..4993a7f --- /dev/null +++ b/.github/workflows/sonarcloud.yml @@ -0,0 +1,105 @@ +name: SonarCloud + +# SonarCloud analysis (Clean as You Code): the "Sonar way" Quality Gate is +# evaluated on NEW CODE only. +# +# Design notes: +# - `sonar.qualitygate.wait=true` is set for pull_request events ONLY: the gate +# then fails this job when new code introduces issues. On the very first push +# to main the whole codebase counts as new code (baseline), so blocking there +# would fail on pre-existing debt by design. +# - The scanner does not auto-detect GitHub Actions, so PR parameters are passed +# explicitly below. +# - Skipped for Dependabot and fork PRs: repository secrets are not available to +# those events, so the job would fail without a token. +on: + push: + branches: [main] + pull_request: + branches: [main] + workflow_dispatch: + +permissions: + contents: read + +jobs: + sonarcloud: + name: SonarCloud analysis + runs-on: ubuntu-latest + if: >- + github.actor != 'dependabot[bot]' && + (github.event_name != 'pull_request' || + github.event.pull_request.head.repo.full_name == github.repository) + services: + mssql: + image: mcr.microsoft.com/mssql/server:2022-latest + env: + SA_PASSWORD: Strong_Passw0rd123! + ACCEPT_EULA: Y + ports: + - 1433:1433 + options: >- + --health-cmd "/opt/mssql-tools18/bin/sqlcmd -S localhost -U sa -P 'Strong_Passw0rd123!' -C -Q 'SELECT 1' || /opt/mssql-tools/bin/sqlcmd -S localhost -U sa -P 'Strong_Passw0rd123!' -Q 'SELECT 1' || exit 1" + --health-interval 10s + --health-timeout 5s + --health-retries 10 + --health-start-period 20s + + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + # Full history: SonarCloud needs blame data to decide which lines are + # "new code" for the Quality Gate. + fetch-depth: 0 + + - name: Setup .NET + uses: actions/setup-dotnet@v4 + with: + dotnet-version: 8.0.x + + - name: Install SonarScanner + run: dotnet tool install --global dotnet-sonarscanner + + - name: Restore dependencies + run: dotnet restore SplitIt.API/SplitIt.Back.sln + + - name: Begin analysis + env: + SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} + PR_KEY: ${{ github.event.pullrequest.number }} + PR_BRANCH: ${{ github.head_ref }} + PR_BASE: ${{ github.base_ref }} + run: | + args=( + /k:santidev21_SplitIt + /o:santidev21 + "/d:sonar.token=$SONAR_TOKEN" + "/d:sonar.cs.opencover.reportsPaths=**/coverage.opencover.xml" + "/d:sonar.cs.vstest.reportsPaths=**/TestResults/*.trx" + ) + if [ "$GITHUB_EVENT_NAME" = "pull_request" ]; then + args+=( + "/d:sonar.pullrequest.key=$PR_KEY" + "/d:sonar.pullrequest.branch=$PR_BRANCH" + "/d:sonar.pullrequest.base=$PR_BASE" + /d:sonar.qualitygate.wait=true + ) + fi + dotnet sonarscanner begin "${args[@]}" + + - name: Build + run: dotnet build SplitIt.API/SplitIt.Back.sln --no-restore -c Release + + - name: Run backend tests with coverage + run: > + dotnet test SplitIt.API/SplitIt.Back.sln + --no-build -c Release + --logger "trx;LogFileName=backend-results.trx" + --collect:"XPlat Code Coverage" + --settings coverlet.runsettings + + - name: End analysis + env: + SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} + run: dotnet sonarscanner end "/d:sonar.token=$SONAR_TOKEN" diff --git a/.gitignore b/.gitignore index 9cefb38..f25fcce 100644 --- a/.gitignore +++ b/.gitignore @@ -198,3 +198,6 @@ Desktop.ini # CodeGraph local index (per-machine, not source) .codegraph/ + +# SonarScanner for .NET working directory +.sonarqube/ From a66922499322fd87dbfda3baed7c94617979c666 Mon Sep 17 00:00:00 2001 From: santidev21 Date: Wed, 30 Sep 2026 21:46:15 -0500 Subject: [PATCH 2/2] fix(sonarcloud): correct GitHub context path for the PR number github.event.pullrequest.number does not exist (the pull_request payload key uses an underscore); the empty value made the scanner reject sonar.pullrequest.key and abort the analysis. --- .github/workflows/sonarcloud.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/sonarcloud.yml b/.github/workflows/sonarcloud.yml index 4993a7f..7b756d7 100644 --- a/.github/workflows/sonarcloud.yml +++ b/.github/workflows/sonarcloud.yml @@ -67,7 +67,7 @@ jobs: - name: Begin analysis env: SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} - PR_KEY: ${{ github.event.pullrequest.number }} + PR_KEY: ${{ github.event.pull_request.number }} PR_BRANCH: ${{ github.head_ref }} PR_BASE: ${{ github.base_ref }} run: |