Skip to content

Commit fbba797

Browse files
samtrionCopilot
andauthored
ci: Created a TestGroup based matrix pipeline (#1092)
* fix(ci): Created a TestGroup based matrix pipeline * chore: Disable CSharpier outside of Visual Studio * fix: Update .github/scripts/Collect-TestProjects.ps1 Co-authored-by: Copilot <[email protected]> Signed-off-by: Martin Stühmer <[email protected]> * fix: Update .github/workflows/step-test.yml Co-authored-by: Copilot <[email protected]> Signed-off-by: Martin Stühmer <[email protected]> --------- Signed-off-by: Martin Stühmer <[email protected]> Co-authored-by: Copilot <[email protected]>
1 parent e9e6202 commit fbba797

File tree

58 files changed

+423
-9
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

58 files changed

+423
-9
lines changed
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
<#
2+
.SYNOPSIS
3+
Retrieves the GitHub Actions 'testgroup' configuration for each test project
4+
and ensures all test projects have a valid configuration.
5+
6+
.DESCRIPTION
7+
Scans all test projects under 'tests', reads '.testgroup' for CI runner configuration,
8+
throws an error if missing, and outputs filtered projects as compressed JSON.
9+
#>
10+
11+
# Get all testgroups from the test projects
12+
$testGroups = Get-ChildItem -Path "tests/NetEvolve.HealthChecks.Tests.Integration" -Recurse -Filter "*.csproj" | ForEach-Object {
13+
$projectDir = $_.Directory.FullName
14+
15+
# Get all .testgroup files in the project directory
16+
$testGroupFile = Join-Path -Path $projectDir -ChildPath ".testgroup"
17+
18+
if (-Not (Test-Path -Path $testGroupFile)) {
19+
throw "Missing .testgroup file in test project: $($_.FullName)"
20+
}
21+
22+
$testGroupContent = Get-Content -Path $testGroupFile -Raw
23+
$testGroupContent.Trim()
24+
25+
# Also validate that each direct subdirectory has a .testgroup file, excluding nested ones and the folder bin, obj, _snapshots and Internals
26+
Get-ChildItem -Path $projectDir -Directory | Where-Object {
27+
$_.Name -notin @("bin", "obj", "_snapshots", "Internals", "Apache", "AWS", "Azure", "GCP")
28+
} | ForEach-Object {
29+
$nestedTestGroupFile = Join-Path -Path $_.FullName -ChildPath ".testgroup"
30+
if (-Not (Test-Path -Path $nestedTestGroupFile)) {
31+
throw "Missing .testgroup file in subdirectory: $($_.FullName) of test project: $($_.FullName)"
32+
}
33+
34+
$nestedTestGroupContent = (Get-Content -Path $nestedTestGroupFile -Raw).Trim()
35+
36+
if ($nestedTestGroupContent -ine 'Disable')
37+
{
38+
$nestedTestGroupContent
39+
}
40+
}
41+
}
42+
43+
# Convert the collected testgroups to compressed JSON format
44+
$testGroupsJson = $testGroups | Sort-Object -Unique | ConvertTo-Json -AsArray -Compress
45+
$testGroupsJson ?? "[]"

.github/workflows/cicd.yml

Lines changed: 163 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,20 +18,175 @@ on:
1818
- detailed
1919
- diagnostic
2020

21+
concurrency:
22+
group: ${{ github.workflow_ref }}@${{ github.ref }}-healthchecks
23+
cancel-in-progress: true
24+
25+
env:
26+
DOTNET_SKIP_FIRST_TIME_EXPERIENCE: 1
27+
DOTNET_CLI_TELEMETRY_OPTOUT: 1
28+
DOTNET_NOLOGO: true
29+
2130
permissions:
2231
actions: read
23-
contents: read
32+
contents: write
2433
pull-requests: write
2534
security-events: write
2635

2736
jobs:
28-
all:
29-
name: Build & Tests
30-
uses: dailydevops/pipelines/.github/workflows/[email protected]
37+
commitlinter:
38+
name: Commit Linter
39+
uses: dailydevops/pipelines/.github/workflows/[email protected]
40+
secrets: inherit
41+
42+
version:
43+
name: Version Management
44+
uses: dailydevops/pipelines/.github/workflows/[email protected]
45+
with:
46+
dotnet-version: ${{ vars.NE_DOTNET_TARGETFRAMEWORKS }}
47+
dotnet-quality: ${{ vars.NE_DOTNET_QUALITY }}
48+
secrets: inherit
49+
50+
format:
51+
name: Code Formatting
52+
uses: dailydevops/pipelines/.github/workflows/[email protected]
53+
needs:
54+
- commitlinter
55+
with:
56+
dotnet-logging: ${{ inputs.dotnet-logging || 'minimal' }}
57+
dotnet-version: ${{ vars.NE_DOTNET_TARGETFRAMEWORKS }}
58+
dotnet-quality: ${{ vars.NE_DOTNET_QUALITY }}
59+
runs-on: 'ubuntu-latest'
60+
secrets: inherit
61+
62+
collect:
63+
name: Collect TestGroups
64+
runs-on: ubuntu-latest
65+
outputs:
66+
testgroups: ${{ steps.collect.outputs.testgroups }}
67+
steps:
68+
- name: Checkout Repository
69+
uses: actions/[email protected]
70+
with:
71+
submodules: recursive
72+
token: ${{ github.token }}
73+
74+
- name: Collect TestGroups
75+
id: collect
76+
shell: pwsh
77+
run: |
78+
$testGroups = .github/scripts/Collect-TestProjects.ps1
79+
echo $testGroups
80+
echo "testgroups=$testGroups" >> $env:GITHUB_OUTPUT
81+
82+
tests-architecture:
83+
name: TestGroup 'Architecture'
84+
needs:
85+
- commitlinter
86+
- collect
87+
- version
88+
uses: ./.github/workflows/step-test.yml
89+
with:
90+
dotnet-logging: ${{ inputs.dotnet-logging || 'minimal' }}
91+
dotnet-version: ${{ vars.NE_DOTNET_TARGETFRAMEWORKS }}
92+
dotnet-quality: ${{ vars.NE_DOTNET_QUALITY }}
93+
execution-name: "Architecture"
94+
runs-on: 'ubuntu-latest'
95+
solution: ./HealthChecks.slnx
96+
solution-version: ${{ needs.version.outputs.solution-version }}
97+
test-path: ./tests/NetEvolve.HealthChecks.Tests.Architecture/NetEvolve.HealthChecks.Tests.Architecture.csproj
98+
secrets: inherit
99+
100+
tests-unit:
101+
name: TestGroup 'Unit'
102+
needs:
103+
- commitlinter
104+
- collect
105+
- version
106+
uses: ./.github/workflows/step-test.yml
31107
with:
32-
enableCleanUpDockerDocker: true
33-
dotnetLogging: ${{ inputs.dotnet-logging }}
34-
dotnetVersion: ${{ vars.NE_DOTNET_TARGETFRAMEWORKS }}
35-
dotnetQuality: ${{ vars.NE_DOTNET_QUALITY }}
108+
dotnet-logging: ${{ inputs.dotnet-logging || 'minimal' }}
109+
dotnet-version: ${{ vars.NE_DOTNET_TARGETFRAMEWORKS }}
110+
dotnet-quality: ${{ vars.NE_DOTNET_QUALITY }}
111+
execution-name: "Unit"
112+
runs-on: 'ubuntu-latest'
36113
solution: ./HealthChecks.slnx
114+
solution-version: ${{ needs.version.outputs.solution-version }}
115+
test-path: ./tests/NetEvolve.HealthChecks.Tests.Unit/NetEvolve.HealthChecks.Tests.Unit.csproj
37116
secrets: inherit
117+
118+
tests-integration:
119+
name: TestGroup '${{ matrix.testgroups }}'
120+
needs:
121+
- commitlinter
122+
- collect
123+
- version
124+
if: ${{ needs.collect.outputs.testgroups != '[]' }}
125+
strategy:
126+
fail-fast: false
127+
matrix:
128+
testgroups: ${{ fromJson(needs.collect.outputs.testgroups) }}
129+
uses: ./.github/workflows/step-test.yml
130+
with:
131+
dotnet-logging: ${{ inputs.dotnet-logging || 'minimal' }}
132+
dotnet-version: ${{ vars.NE_DOTNET_TARGETFRAMEWORKS }}
133+
dotnet-quality: ${{ vars.NE_DOTNET_QUALITY }}
134+
execution-name: "integration-${{ matrix.testgroups }}"
135+
runs-on: 'ubuntu-latest'
136+
solution: ./HealthChecks.slnx
137+
solution-version: ${{ needs.version.outputs.solution-version }}
138+
test-filter: "/*/*/*/*[TestGroup=${{ matrix.testgroups }}]"
139+
test-path: ./tests/NetEvolve.HealthChecks.Tests.Integration/NetEvolve.HealthChecks.Tests.Integration.csproj
140+
secrets: inherit
141+
142+
coverage:
143+
name: Collect Code Coverage
144+
needs:
145+
- tests-architecture
146+
- tests-integration
147+
- tests-unit
148+
uses: ./.github/workflows/step-coverage.yml
149+
with:
150+
runs-on: 'ubuntu-latest'
151+
solution: ./HealthChecks.slnx
152+
secrets: inherit
153+
154+
build:
155+
name: Build Solution
156+
if: ${{ !cancelled() && !failure() }}
157+
uses: dailydevops/pipelines/.github/workflows/[email protected]
158+
needs:
159+
- coverage
160+
- format
161+
- version
162+
with:
163+
dotnet-logging: ${{ inputs.dotnet-logging || 'minimal' }}
164+
dotnet-version: ${{ vars.NE_DOTNET_TARGETFRAMEWORKS }}
165+
dotnet-quality: ${{ vars.NE_DOTNET_QUALITY }}
166+
runs-on: 'ubuntu-latest'
167+
solution: ./HealthChecks.slnx
168+
solution-version: ${{ needs.version.outputs.solution-version }}
169+
secrets: inherit
170+
171+
cleanup:
172+
name: Cleanup Build Files
173+
runs-on: ubuntu-latest
174+
needs:
175+
- coverage
176+
if: ${{ always() }}
177+
steps:
178+
- name: Delete Build Artifact
179+
uses: geekyeggo/[email protected]
180+
with:
181+
name: |
182+
build-files
183+
failOnError: false
184+
185+
dependabot:
186+
name: Dependabot Merge
187+
if: ${{ !cancelled() && !failure() && github.event_name == 'pull_request' && github.actor == 'dependabot[bot]' }}
188+
uses: dailydevops/pipelines/.github/workflows/[email protected]
189+
needs:
190+
- build
191+
secrets: inherit
192+
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
on:
2+
workflow_call:
3+
inputs:
4+
runs-on:
5+
required: false
6+
type: string
7+
default: ubuntu-latest
8+
solution:
9+
required: true
10+
type: string
11+
secrets:
12+
CODECOV_TOKEN:
13+
required: false
14+
15+
permissions:
16+
contents: read
17+
18+
jobs:
19+
testing:
20+
name: Testing .NET solution
21+
runs-on: ${{ inputs.runs-on || 'ubuntu-latest' }}
22+
env:
23+
codecov_token: ${{ secrets.CODECOV_TOKEN }}
24+
25+
steps:
26+
- name: Download Build files
27+
uses: actions/[email protected]
28+
with:
29+
pattern: coverage-*
30+
merge-multiple: true
31+
32+
- name: List all Files
33+
run: |
34+
ls -r ${{ github.workspace }}
35+
36+
- name: ReportGenerator
37+
uses: danielpalme/[email protected]
38+
with:
39+
reports: '${{ github.workspace }}/**/*.cobertura.xml'
40+
targetdir: '${{ github.workspace }}/coveragereports'
41+
reporttypes: 'Cobertura;MarkdownSummaryGithub'
42+
43+
- name: Upload coverage into summary
44+
if: ${{ runner.os != 'Windows' }}
45+
run: |
46+
cat $GITHUB_WORKSPACE/coveragereports/SummaryGithub.md >> $GITHUB_STEP_SUMMARY
47+
48+
- name: Update codecov
49+
uses: codecov/[email protected]
50+
if: ${{ env.codecov_token != '' }}
51+
with:
52+
token: ${{ env.codecov_token }}
53+
fail_ci_if_error: true
54+
files: ${{ github.workspace }}/coveragereports/Cobertura.xml
55+
56+
- name: Upload ReportGenerator
57+
uses: actions/[email protected]
58+
if: always()
59+
with:
60+
name: reportgenerator-${{ inputs.runs-on || 'ubuntu-latest' }}-${{ hashFiles(inputs.solution) }}
61+
path: |
62+
${{ github.workspace }}/coveragereports/**/*.*

.github/workflows/step-test.yml

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
on:
2+
workflow_call:
3+
inputs:
4+
dotnet-logging:
5+
required: false
6+
type: string
7+
default: quiet
8+
dotnet-version:
9+
required: false
10+
type: string
11+
default: 8.x
12+
dotnet-quality:
13+
required: false
14+
type: string
15+
default: ga
16+
execution-name:
17+
required: true
18+
type: string
19+
default: default
20+
runs-on:
21+
required: false
22+
type: string
23+
default: ubuntu-latest
24+
solution:
25+
required: true
26+
type: string
27+
solution-version:
28+
required: true
29+
type: string
30+
test-filter:
31+
required: false
32+
type: string
33+
default: ''
34+
test-path:
35+
required: true
36+
type: string
37+
secrets:
38+
CODECOV_TOKEN:
39+
required: false
40+
41+
permissions:
42+
contents: write
43+
44+
env:
45+
NUGET_PACKAGES: ${{ github.workspace }}/.nuget/packages
46+
47+
jobs:
48+
testing:
49+
name: Testing .NET solution
50+
runs-on: ${{ inputs.runs-on || 'ubuntu-latest' }}
51+
env:
52+
codecov_token: ${{ secrets.CODECOV_TOKEN }}
53+
54+
steps:
55+
- name: Checkout repository
56+
uses: actions/[email protected]
57+
with:
58+
fetch-depth: 0
59+
submodules: recursive
60+
token: ${{ github.token }}
61+
62+
- name: Setup .NET
63+
uses: actions/[email protected]
64+
with:
65+
dotnet-version: ${{ inputs.dotnet-version || '10.x' }}
66+
global-json-file: ./global.json
67+
68+
- name: Restore dependencies
69+
run: dotnet restore ${{ inputs.solution }} -v ${{ inputs.dotnet-logging || 'minimal' }}
70+
71+
- name: Build
72+
run: dotnet build ${{ inputs.solution }} -c Release -v ${{ inputs.dotnet-logging || 'minimal' }} --no-restore /p:GeneratePackageOnBuild=false /p:Version=${{ inputs.solution-version }}
73+
74+
- name: Test
75+
id: test
76+
env:
77+
TUNIT_DISABLE_GITHUB_REPORTER: true
78+
run: |
79+
dotnet test \
80+
--project ${{ inputs.test-path }} \
81+
-c Release \
82+
-v ${{ inputs.dotnet-logging || 'minimal' }} \
83+
--no-build \
84+
--no-restore \
85+
/p:Version=${{ inputs.solution-version }} \
86+
--results-directory ./TestResults \
87+
${{ inputs.test-filter != '' && format('--treenode-filter "{0}"', inputs.test-filter) || ''}} \
88+
-- \
89+
--coverage \
90+
--coverage-output-format cobertura
91+
92+
- name: Upload Coverage Reports
93+
uses: actions/[email protected]
94+
with:
95+
name: coverage-${{ inputs.runs-on || 'ubuntu-latest' }}-${{ hashFiles(inputs.solution) }}-${{ inputs.execution-name }}
96+
path: |
97+
**/*.cobertura.xml

0 commit comments

Comments
 (0)