Skip to content

Commit 1e2ad7c

Browse files
authored
Report code coverage to GitHub (#4574)
1 parent 44b5773 commit 1e2ad7c

File tree

4 files changed

+53
-57
lines changed

4 files changed

+53
-57
lines changed

azure-pipelines.yml

Lines changed: 4 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -56,27 +56,18 @@ variables:
5656

5757
- name: runAsPublic
5858
value: ${{ eq(variables['System.TeamProject'], 'public') }}
59+
5960
- name: _BuildConfig
6061
value: Release
6162
- name: isOfficialBuild
6263
value: ${{ and(ne(variables['runAsPublic'], 'true'), notin(variables['Build.Reason'], 'PullRequest')) }}
63-
- name: IsDeltaBuild
64-
value: ${{ eq(variables['Build.Reason'], 'PullRequest') }}
6564
- name: Build.Arcade.ArtifactsPath
6665
value: $(Build.SourcesDirectory)/artifacts/
6766
- name: Build.Arcade.LogsPath
6867
value: $(Build.Arcade.ArtifactsPath)log/$(_BuildConfig)/
6968
- name: Build.Arcade.TestResultsPath
7069
value: $(Build.Arcade.ArtifactsPath)TestResults/$(_BuildConfig)/
7170

72-
# For full build we can do a shallow build, for a delta build we need the full history.
73-
- ${{ if eq(variables['IsDeltaBuild'], 'true') }}:
74-
- name: _FetchDepth
75-
value: 0
76-
- ${{ else }}:
77-
- name: _FetchDepth
78-
value: 1
79-
8071
- ${{ if or(startswith(variables['Build.SourceBranch'], 'refs/heads/release/'), startswith(variables['Build.SourceBranch'], 'refs/heads/internal/release/'), eq(variables['Build.Reason'], 'Manual')) }}:
8172
- name: PostBuildSign
8273
value: false
@@ -163,7 +154,7 @@ stages:
163154
- checkout: self
164155
clean: true
165156
persistCredentials: true
166-
fetchDepth: $(_FetchDepth)
157+
fetchDepth: 1
167158

168159
steps:
169160
- template: /eng/pipelines/templates/BuildAndTest.yml
@@ -173,7 +164,6 @@ stages:
173164
repoLogPath: $(Build.Arcade.LogsPath)
174165
repoTestResultsPath: $(Build.Arcade.TestResultsPath)
175166
skipQualityGates: ${{ eq(variables['SkipQualityGates'], 'true') }}
176-
isDeltaBuild: $(IsDeltaBuild)
177167
isWindows: true
178168
warnAsError: 0
179169

@@ -200,7 +190,7 @@ stages:
200190
- checkout: self
201191
clean: true
202192
persistCredentials: true
203-
fetchDepth: $(_FetchDepth)
193+
fetchDepth: 1
204194

205195
steps:
206196
- template: /eng/pipelines/templates/BuildAndTest.yml
@@ -210,7 +200,6 @@ stages:
210200
repoLogPath: $(Build.Arcade.LogsPath)
211201
repoTestResultsPath: $(Build.Arcade.TestResultsPath)
212202
skipQualityGates: ${{ eq(variables['SkipQualityGates'], 'true') }}
213-
isDeltaBuild: $(IsDeltaBuild)
214203
isWindows: false
215204
warnAsError: 0
216205

@@ -262,8 +251,6 @@ stages:
262251
displayName: Init toolset
263252

264253
- template: /eng/pipelines/templates/VerifyCoverageReport.yml
265-
parameters:
266-
isDeltaBuild: $(IsDeltaBuild)
267254

268255

269256
# ----------------------------------------------------------------
@@ -304,7 +291,7 @@ stages:
304291
- checkout: self
305292
clean: true
306293
persistCredentials: true
307-
fetchDepth: $(_FetchDepth)
294+
fetchDepth: 1
308295

309296
steps:
310297
- template: \eng\pipelines\templates\BuildAndTest.yml
@@ -315,7 +302,6 @@ stages:
315302
repoTestResultsPath: $(Build.Arcade.TestResultsPath)
316303
skipTests: true
317304
skipQualityGates: true
318-
isDeltaBuild: $(IsDeltaBuild)
319305
isWindows: false
320306

321307

eng/pipelines/templates/BuildAndTest.yml

Lines changed: 0 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,6 @@ parameters:
77
type: string
88
- name: repoTestResultsPath
99
type: string
10-
- name: isDeltaBuild
11-
type: string
1210
- name: isWindows
1311
type: string
1412
- name: skipTests
@@ -22,24 +20,6 @@ parameters:
2220
default: 1
2321

2422
steps:
25-
# Debug
26-
# - pwsh: |
27-
# Write-Host 'buildScript: ${{ parameters.buildScript }}'
28-
# Write-Host 'buildConfig: ${{ parameters.buildConfig }}'
29-
# Write-Host 'repoLogPath: ${{ parameters.repoLogPath }}'
30-
# Write-Host 'repoTestResultsPath: ${{ parameters.repoTestResultsPath }}'
31-
# Write-Host 'isDeltaBuild: ${{ parameters.isDeltaBuild }}'
32-
# Write-Host 'isWindows: ${{ parameters.isWindows }}'
33-
# Write-Host 'skipTests: ${{ parameters.skipTests }}'
34-
# Write-Host 'skipQualityGates: ${{ parameters.skipQualityGates }}'
35-
# Get-ChildItem env:* | Sort-Object Name
36-
# displayName: Debug
37-
38-
- pwsh: |
39-
function Export { param($i); Write-Host "$i"; Write-Host "##$i" }
40-
Export "vso[task.setvariable variable=IsDeltaBuild]${{ parameters.isDeltaBuild }}"
41-
displayName: Set flags
42-
4323
- script: ${{ parameters.buildScript }}
4424
-restore
4525
/bl:${{ parameters.repoLogPath }}/restore.binlog

eng/pipelines/templates/VerifyCoverageReport.yml

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,3 @@
1-
parameters:
2-
- name: isDeltaBuild
3-
type: string
4-
51
steps:
62
- task: DownloadBuildArtifacts@0
73
displayName: Download code coverage reports
@@ -34,3 +30,12 @@ steps:
3430
- pwsh: |
3531
$(Build.SourcesDirectory)/eng/scripts/ValidateProjectCoverage.ps1 -CoberturaReportXml ./merged.cobertura.xml
3632
displayName: Check per-project coverage
33+
34+
- ${{ if and(eq(variables['System.TeamProject'], 'public'), eq(variables['Build.Reason'], 'PullRequest')) }}:
35+
- task: GitHubComment@0
36+
condition: always()
37+
inputs:
38+
gitHubConnection: dotnet-comment-bot-service-connection
39+
repositoryName: '$(Build.Repository.Name)'
40+
id: $(System.PullRequest.PullRequestNumber)
41+
displayName: Report coverage to GitHub

eng/scripts/ValidateProjectCoverage.ps1

Lines changed: 40 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
#!/usr/bin/env pwsh
2-
32
<#
43
.SYNOPSIS
54
Validates the code coverage policy for each project.
@@ -58,6 +57,8 @@ Get-ChildItem -Path src -Include '*.*sproj' -Recurse | ForEach-Object {
5857
$esc = [char]27
5958
$Errors = New-Object System.Collections.ArrayList
6059
$Kudos = New-Object System.Collections.ArrayList
60+
$ErrorsMarkdown = @();
61+
$KudosMarkdown = @();
6162

6263
Write-Verbose "Collecting projects from code coverage report..."
6364
$CoberturaReport.coverage.packages.package | ForEach-Object {
@@ -80,10 +81,11 @@ $CoberturaReport.coverage.packages.package | ForEach-Object {
8081
# Detect the under-coverage
8182
if ($MinCodeCoverage -gt $LineCoverage) {
8283
$IsFailed = $true
84+
$ErrorsMarkdown += "| $Name | Line | **$MinCodeCoverage** | $LineCoverage :small_red_triangle_down: |"
8385
[void]$Errors.Add(
8486
(
8587
New-Object PSObject -Property @{
86-
"Project" = $Name;
88+
"Project" = $Name.Replace('Microsoft.Extensions.', 'M.E.').Replace('Microsoft.AspNetCore.', 'M.AC.');
8789
"Coverage Type" = "Line";
8890
"Expected" = $MinCodeCoverage;
8991
"Actual" = "$esc[1m$esc[0;31m$($LineCoverage)$esc[0m"
@@ -94,10 +96,11 @@ $CoberturaReport.coverage.packages.package | ForEach-Object {
9496

9597
if ($MinCodeCoverage -gt $BranchCoverage) {
9698
$IsFailed = $true
99+
$ErrorsMarkdown += "| $Name | Branch | **$MinCodeCoverage** | $BranchCoverage :small_red_triangle_down: |"
97100
[void]$Errors.Add(
98101
(
99102
New-Object PSObject -Property @{
100-
"Project" = $Name;
103+
"Project" = $Name.Replace('Microsoft.Extensions.', 'M.E.').Replace('Microsoft.AspNetCore.', 'M.AC.');
101104
"Coverage Type" = "Branch";
102105
"Expected" = $MinCodeCoverage;
103106
"Actual" = "$esc[1m$esc[0;31m$($BranchCoverage)$esc[0m"
@@ -110,10 +113,11 @@ $CoberturaReport.coverage.packages.package | ForEach-Object {
110113
[int]$lowestReported = [math]::Min([math]::Truncate($LineCoverage), [math]::Truncate($BranchCoverage));
111114
Write-Debug "line: $LineCoverage, branch: $BranchCoverage, min: $lowestReported, threshold: $MinCodeCoverage"
112115
if ([int]$MinCodeCoverage -lt $lowestReported) {
116+
$KudosMarkdown += "| $Name | $MinCodeCoverage | **$lowestReported** |"
113117
[void]$Kudos.Add(
114118
(
115119
New-Object PSObject -Property @{
116-
"Project" = $Name;
120+
"Project" = $Name.Replace('Microsoft.Extensions.', 'M.E.').Replace('Microsoft.AspNetCore.', 'M.AC.');
117121
"Expected" = $MinCodeCoverage;
118122
"Actual" = "$esc[1m$esc[0;32m$($lowestReported)$esc[0m";
119123
}
@@ -129,8 +133,7 @@ $CoberturaReport.coverage.packages.package | ForEach-Object {
129133
}
130134
}
131135

132-
if ($Kudos.Count -ne 0)
133-
{
136+
if ($Kudos.Count -ne 0) {
134137
Write-Header -message "`r`nGood job! The coverage increased" -isError $false
135138
$Kudos | `
136139
Sort-Object Project | `
@@ -139,6 +142,37 @@ if ($Kudos.Count -ne 0)
139142
@{ Name="Actual"; Expression="Actual"; Width=10; Alignment = "Right" } `
140143
-AutoSize -Wrap
141144
Write-Host "##vso[task.logissue type=warning;]Good job! The coverage increased, please update your projects"
145+
146+
$KudosMarkdown = @(':tada: **Good job! The coverage increased** :tada:', 'Update `MinCodeCoverage` in the project files.', "`r`n", '| Project | Expected | Actual |', '| --- | ---: | ---: |', $KudosMarkdown, "`r`n`r`n");
147+
}
148+
149+
if ($Errors.Count -ne 0) {
150+
Write-Header -message "`r`n[!!] Found $($Errors.Count) issues!" -isError ($Errors.Count -ne 0)
151+
$Errors | `
152+
Sort-Object Project, 'Coverage Type' | `
153+
Format-Table "Project", `
154+
@{ Name="Expected"; Expression="Expected"; Width=10; Alignment = "Right" }, `
155+
@{ Name="Actual"; Expression="Actual"; Width=10; Alignment = "Right" }, `
156+
@{ Name="Coverage Type"; Expression="Coverage Type"; Width=10; Alignment = "Center" } `
157+
-AutoSize -Wrap
158+
159+
$ErrorsMarkdown = @(":bangbang: **Found issues** :bangbang: ", "`r`n", '| Project | Coverage Type |Expected | Actual | ', '| --- | :---: | ---: | ---: |', $ErrorsMarkdown, "`r`n`r`n");
160+
}
161+
162+
# Write out markdown for publishing back to AzDO
163+
'' | Out-File coverage-report.md -Encoding ascii
164+
$ErrorsMarkdown | Out-File coverage-report.md -Encoding ascii -Append
165+
$KudosMarkdown | Out-File coverage-report.md -Encoding ascii -Append
166+
167+
# Set the AzDO variable used by GitHubComment@0 task
168+
[string]$markdown = Get-Content coverage-report.md -Raw
169+
if (![string]::IsNullOrWhiteSpace($markdown)) {
170+
# Add link back to the Code Coverage board
171+
$link = "$($env:SYSTEM_COLLECTIONURI)$env:SYSTEM_TEAMPROJECT/_build/results?buildId=$env:BUILD_BUILDID&view=codecoverage-tab"
172+
$markdown = "$markdown`n`nFull code coverage report: $link"
173+
174+
$gitHubCommentVar = '##vso[task.setvariable variable=GITHUB_COMMENT]' + $markdown.Replace("`r`n","`n").Replace("`n","%0D%0A")
175+
Write-Host $gitHubCommentVar
142176
}
143177

144178
if ($Errors.Count -eq 0)
@@ -147,13 +181,4 @@ if ($Errors.Count -eq 0)
147181
exit 0;
148182
}
149183

150-
Write-Header -message "`r`n[!!] Found $($Errors.Count) issues!" -isError ($Errors.Count -ne 0)
151-
$Errors | `
152-
Sort-Object Project, 'Coverage Type' | `
153-
Format-Table "Project", `
154-
@{ Name="Expected"; Expression="Expected"; Width=10; Alignment = "Right" }, `
155-
@{ Name="Actual"; Expression="Actual"; Width=10; Alignment = "Right" }, `
156-
@{ Name="Coverage Type"; Expression="Coverage Type"; Width=10; Alignment = "Center" } `
157-
-AutoSize -Wrap
158184
exit -1;
159-

0 commit comments

Comments
 (0)