-
Notifications
You must be signed in to change notification settings - Fork 0
185 lines (170 loc) · 9.72 KB
/
Copy pathsonar.yml
File metadata and controls
185 lines (170 loc) · 9.72 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
# Nightly static analysis with coverage, against the project's own analysis server.
#
# Triggers on `schedule` and `workflow_dispatch` only. Never on `pull_request`, and under no
# circumstance on `pull_request_target`: the analysis token is a secret that reaches a private
# server, and `pull_request_target` runs a fork's code in this repository's context with access to
# secrets. A `pull_request` run would get no secrets and simply fail, which is noise; the build
# workflow is what gates a pull request.
#
# 04:00 UTC keeps it clear of the other nightly runs that share the analysis server.
#
# Coverage comes from the Microsoft Testing Platform's own extension rather than a coverlet wrapper:
# under MTP's AssemblyLoadContext coverlet did not instrument the production assemblies, and every
# nightly run reported 0%. `--coverage --coverage-output-format xml` writes Visual-Studio-Coverage
# XML, which is what sonar.cs.vscoveragexml.reportsPaths below reads.
#
# The integration suites are excluded — they need Testcontainers and run in integration.yml — with one
# exception: the Orleans suite's in-process tests are collected too, because they are what verifies the
# execution model. Its kill tests run the silo in a second process and are not run here.
# Stratara.Benchmarks is excluded by the *.Tests.csproj glob.
name: Analysis
on:
schedule:
- cron: '0 4 * * *'
workflow_dispatch:
permissions:
contents: read
concurrency:
group: analysis-${{ github.ref }}
cancel-in-progress: false
jobs:
analyse:
name: Static analysis + coverage
runs-on: ubuntu-latest
# The Orleans integration suite's in-process tests take around a quarter of an hour on top.
timeout-minutes: 90
env:
BUILD_CONFIGURATION: Debug
COVERAGE_DIR: ${{ github.workspace }}/TestResults/coverage
steps:
- uses: actions/checkout@v4
with:
# A shallow clone makes the scanner attribute every line to the checkout commit, which
# ruins new-code measurement.
fetch-depth: 0
- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
global-json-file: global.json
- name: Install the scanner
run: dotnet tool install --global dotnet-sonarscanner
# Every property is passed here. The .NET scanner does not read a sonar-project.properties and
# in fact refuses to post-process while one exists, which is why the repository no longer has
# one — it was documentation of this list, and documentation that disagreed with it in places.
#
# What the exclusions are for:
# Contracts, Diagnostics wire-level records, ActivitySource / Meter / log schema
# Identity.AspNetCore ASP.NET Core identity wiring, host glue
# ServiceDefaults[.AspNetCore] OpenTelemetry + Serilog + host bootstrap
# *Command/Query/Event(s)/Dto/Options.cs data carriers and dispatch glue
# *DbContext.cs EF Core configuration plumbing
# LogEvents.cs the source-generated [LoggerMessage] schema
# Program.cs, Migrations/** host entry point and EF migrations
# Sonar counts a file with no coverage data as 0% covered, so excluding the data-only ones is
# what keeps the number about behaviour rather than about records.
#
# src/Stratara.Orleans is in the coverage measure since it ships as a package. Unit tests alone
# would read as nearly nothing for it — the silo's grains are verified on a real cluster — so the
# Orleans integration suite's in-process tests contribute their coverage below. Its kill tests
# run the silo in a second process, whose coverage no collector here sees, and are left out.
# sonar.sources and sonar.tests are deliberately absent: the .NET scanner derives both from
# the MSBuild analysis, and the old pipeline never set them either.
- name: Begin analysis
env:
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
SONAR_HOST_URL: ${{ vars.SONAR_HOST_URL }}
run: |
dotnet sonarscanner begin \
/k:"stratara" \
/n:"Stratara" \
/d:sonar.token="${SONAR_TOKEN}" \
/d:sonar.host.url="${SONAR_HOST_URL}" \
/d:sonar.exclusions='**/bin/**,**/obj/**,**/TestResults/**,artifacts/**,reports/**,samples/**,scripts/**,tools/**,**/*.g.cs,tmp/**,docs/**,.junie/**' \
/d:sonar.coverage.exclusions='src/Stratara.Contracts/**,src/Stratara.Diagnostics/**,src/Stratara.Identity.AspNetCore/**,src/Stratara.ServiceDefaults/**,src/Stratara.ServiceDefaults.AspNetCore/**,**/*Command.cs,**/*Query.cs,**/*Event.cs,**/*Events.cs,**/*DbContext.cs,**/*Dto.cs,**/*Options.cs,**/LogEvents.cs,**/Program.cs,**/Migrations/**' \
/d:sonar.cpd.exclusions='src/Stratara.Contracts/**/*.cs,**/*Dto.cs,**/*Options.cs,**/*Event.cs,**/*Events.cs' \
/d:sonar.cs.file.suffixes=.cs \
/d:sonar.sourceEncoding=UTF-8 \
/d:sonar.qualitygate.wait=true \
/d:sonar.cs.vscoveragexml.reportsPaths="${COVERAGE_DIR}/*.coverage.xml" \
/d:sonar.issue.ignore.multicriteria=ireadonlyListConvention,constantArraysInTests,staticMethodsInTests,docCommentsLookLikeCode \
/d:sonar.issue.ignore.multicriteria.ireadonlyListConvention.ruleKey=external_roslyn:CA1859 \
/d:sonar.issue.ignore.multicriteria.ireadonlyListConvention.resourceKey='**' \
/d:sonar.issue.ignore.multicriteria.constantArraysInTests.ruleKey=external_roslyn:CA1861 \
/d:sonar.issue.ignore.multicriteria.constantArraysInTests.resourceKey='tests/**' \
/d:sonar.issue.ignore.multicriteria.staticMethodsInTests.ruleKey=external_roslyn:CA1822 \
/d:sonar.issue.ignore.multicriteria.staticMethodsInTests.resourceKey='tests/**' \
/d:sonar.issue.ignore.multicriteria.docCommentsLookLikeCode.ruleKey=csharpsquid:S125 \
/d:sonar.issue.ignore.multicriteria.docCommentsLookLikeCode.resourceKey='src/**'
- name: Restore
run: dotnet restore Stratara.Publish.slnf
- name: Build
run: dotnet build Stratara.Publish.slnf -c "${BUILD_CONFIGURATION}" --no-restore --nologo
# `dotnet test ... --` so MTP receives the coverage arguments. Running the dll directly hands
# them to xUnit, which rejects --coverage as an unknown option.
- name: Unit tests with coverage
shell: bash
run: |
set -uo pipefail
mkdir -p "${COVERAGE_DIR}"
failed=0
for proj in tests/*/*.Tests.csproj; do
[[ -f "${proj}" ]] || continue
[[ "${proj}" == *IntegrationTests* ]] && continue
name="$(basename "$(dirname "${proj}")")"
echo ""
echo "=== Coverage: ${name} ==="
dotnet test "${proj}" --no-build -c "${BUILD_CONFIGURATION}" -- \
--coverage \
--coverage-output-format xml \
--coverage-output "${COVERAGE_DIR}/${name}.coverage.xml" \
|| failed=1
done
exit ${failed}
# The Orleans integration project is not in the publish filter, so it is restored and built here.
- name: Build the Orleans integration tests
run: dotnet build tests/Stratara.Orleans.IntegrationTests/Stratara.Orleans.IntegrationTests.csproj -c "${BUILD_CONFIGURATION}" --nologo
# The in-process tests, on Testcontainers. A failing test is a warning here rather than a failed
# job: integration.yml is the gate for the suite, and a failure here must not skip the analysis.
- name: Orleans integration tests with coverage
shell: bash
run: |
set -uo pipefail
mkdir -p "${COVERAGE_DIR}"
suite=Stratara.Orleans.IntegrationTests
dotnet test "tests/${suite}/${suite}.csproj" --no-build -c "${BUILD_CONFIGURATION}" -- \
--coverage \
--coverage-output-format xml \
--coverage-output "${COVERAGE_DIR}/${suite}.coverage.xml" \
--filter-not-class "${suite}.Aggregates.DurableIntentTests" \
--filter-not-class "${suite}.HeavyWork.HeavyBurstTests" \
--filter-not-class "${suite}.Timers.HardKillTimerTests" \
--filter-not-class "${suite}.Projections.CommitPublishKillTests" \
--filter-not-class "${suite}.Sagas.SagaProcessTimeoutTests" \
--filter-not-class "${suite}.Hosting.TwoSiloKillTests" \
|| echo "::warning::The Orleans integration tests failed in the analysis run; integration.yml is the gate for them."
# `end` submits the analysis and, because the begin step asked for it, waits for the server's
# verdict rather than finishing at "uploaded". Without the wait this job is green whatever the
# analysis found — worse than no analysis, because it looks like a check.
- name: End analysis and wait for the quality gate
env:
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
run: dotnet sonarscanner end /d:sonar.token="${SONAR_TOKEN}"
# A report of what the run found, on the run's own summary page. Best-effort: a failure here
# does not invalidate the analysis, which has already been submitted.
- name: Export the results
if: always()
continue-on-error: true
env:
SONARQUBE_URL: ${{ vars.SONAR_HOST_URL }}
SONARQUBE_TOKEN: ${{ secrets.SONAR_TOKEN }}
BUILD_ARTIFACT_DIR: ${{ github.workspace }}/TestResults/analysis
run: |
mkdir -p "${BUILD_ARTIFACT_DIR}"
bash scripts/ci/export-sonarqube-results.sh
- name: Upload the analysis report
if: always()
uses: actions/upload-artifact@v4
with:
name: analysis-report
path: TestResults/analysis
if-no-files-found: ignore