Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Code Coverage #11

Merged
merged 21 commits into from
Apr 24, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
c33a518
Add code coverage support
natescherer Apr 1, 2021
0cd0250
Wrap reportgenerator params in quotes
natescherer Apr 1, 2021
dd58b94
Adjust coverage file names to match ReportGenerator output
natescherer Apr 1, 2021
4117825
Add temporary logging
natescherer Apr 1, 2021
bfcaed6
Add TextSummary and sourcedirs to ReportGenerator
natescherer Apr 1, 2021
ae23dbf
Send text summary of coverage via check run
natescherer Apr 1, 2021
b8e6b5a
Fix typos
natescherer Apr 1, 2021
77c708d
Adjust logging
natescherer Apr 1, 2021
e94991d
Fix typo
natescherer Apr 1, 2021
d34417c
Switch to using coverage summary in gist
natescherer Apr 1, 2021
440ea5a
Adjust ReportGenerator output
natescherer Apr 1, 2021
653d612
Updating Accept to v3 per doc recommendations
natescherer Apr 1, 2021
a714c95
Send text summary via check run
natescherer Apr 1, 2021
b9f13d8
Clean up coverage reporting for release
natescherer Apr 1, 2021
b371eea
Add looping and recurstion to make sure all ps1 and psm1 files under …
natescherer Apr 1, 2021
5084b86
Document code coverage inputs and outputs
natescherer Apr 1, 2021
8d3f743
Merge branch 'master' of https://github.com/zyborg/pester-tests-repor…
natescherer Apr 8, 2021
d9cd76b
Merge branch 'zyborg-master' into feature/code-coverage
natescherer Apr 8, 2021
4795b43
Add closing brace missed in merge
natescherer Apr 8, 2021
31ae861
Change to txt file extension for coverage gist
natescherer Apr 9, 2021
89f0729
Switch to XSL generated coverage report
natescherer Apr 16, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,11 @@ This Action defines the following formal inputs.
| **`gist_badge_label`** | false | If specified, the Test Report Gist will also include an adjacent badge rendered with the status of the associated Test Report and and label content of this input. In addition to any static text you can provide _escape tokens_ of the form `%name%` where name can be the name of any field returned from a Pester Result, such as `ExecutedAt` or `Result`. If you want a literal percent, just specify an empty name as in `%%`.
| **`gist_badge_message`** | false | If Gist badge generation is enabled by providing a value for the `gist_badge_label` input, this input allows you to override the default message on the badge, which is equivalent to the the Pester Result `Status` such as `Failed` or `Passed`. As with the label input, you can specify escape tokens in addition to literal text. See the label input description for more details.
| **`gist_token`** | false | GitHub OAuth/PAT token to be used for accessing Gist to store test results report. The integrated GITHUB_TOKEN that is normally accessible during a Workflow does not include read/write permissions to associated Gists, therefore a separate token is needed. You can control which account is used to actually store the state by generating a token associated with the target account.
| **`coverage_paths`** | false | Comma-separated list of one or more directories to scan for code coverage, relative to the root of the project. Will include all .ps1 and .psm1 files under these directories recursively.
| **`coverage_report_name`** | false | The name of the code coverage report object that will be attached to the Workflow Run. Defaults to the name `COVERAGE_RESULTS_<datetime>` where `<datetime>` is in the form `yyyyMMdd_hhmmss`.
| **`coverage_report_title`** | false | The title of the code coverage report that will be embedded in the report itself, which defaults to the same as the `code_coverage_report_name` input.
| **`coverage_gist`** | false | If true, will attach the coverage results to the gist specified in `gist_name`.
| **`coverage_gist_badge_label`** | false | If specified, the Test Report Gist will also include an adjacent badge rendered with the percentage of the associated Coverage Report and label content of this input.
| **`tests_fail_step`** | false | If true, will cause the step to fail if one or more tests fails.


Expand All @@ -116,6 +121,7 @@ This Action defines the following formal outputs.
| **`total_count`** | Total number of tests discovered.
| **`passed_count`** | Total number of tests passed.
| **`failed_count`** | Total number of tests failed.
| **`coverage_results_path`** | Path to the code coverage results file in JaCoCo XML format.

### PowerShell GitHub Action

Expand Down
116 changes: 109 additions & 7 deletions action.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,11 @@ $inputs = @{
gist_token = Get-ActionInput gist_token
gist_badge_label = Get-ActionInput gist_badge_label
gist_badge_message = Get-ActionInput gist_badge_message
coverage_paths = Get-ActionInput coverage_paths
coverage_report_name = Get-ActionInput coverage_report_name
coverage_report_title = Get-ActionInput coverage_report_title
coverage_gist = Get-ActionInput coverage_gist
coverage_gist_badge_label = Get-ActionInput coverage_gist_badge_label
tests_fail_step = Get-ActionInput tests_fail_step
}

Expand All @@ -65,6 +70,7 @@ else {
$exclude_paths = splitListInput $inputs.exclude_paths
$include_tags = splitListInput $inputs.include_tags
$exclude_tags = splitListInput $inputs.exclude_tags
$coverage_paths = splitListInput $inputs.coverage_paths
$output_level = splitListInput $inputs.output_level

Write-ActionInfo "Running Pester tests with following:"
Expand Down Expand Up @@ -111,6 +117,19 @@ else {
$pesterConfig.Output.Verbosity = $output_level
}

if ($coverage_paths) {
Write-ActionInfo " * coverage_paths:"
writeListInput $coverage_paths
$coverageFiles = @()
foreach ($path in $coverage_paths) {
$coverageFiles += Get-ChildItem $Path -Recurse -Include @("*.ps1","*.psm1") -Exclude "*.Tests.ps1"
}
$pesterConfig.CodeCoverage.Enabled = $true
$pesterConfig.CodeCoverage.Path = $coverageFiles
$coverage_results_path = Join-Path $test_results_dir coverage.xml
$pesterConfig.CodeCoverage.OutputPath = $coverage_results_path
}

if ($inputs.tests_fail_step) {
Write-ActionInfo " * tests_fail_step: true"
}
Expand Down Expand Up @@ -211,9 +230,33 @@ function Build-MarkdownReport {
}
}

function Build-CoverageReport {
Write-ActionInfo "Building human-readable code-coverage report"
$script:coverage_report_name = $inputs.coverage_report_name
$script:coverage_report_title = $inputs.coverage_report_title

if (-not $script:coverage_report_name) {
$script:coverage_report_name = "COVERAGE_RESULTS_$([datetime]::Now.ToString('yyyyMMdd_hhmmss'))"
}
if (-not $coverage_report_title) {
$script:coverage_report_title = $report_name
}

$script:coverage_report_path = Join-Path $test_results_dir coverage-results.md
& "$PSScriptRoot/jacoco-report/jacocoxml2md.ps1" -Verbose `
-xmlFile $script:coverage_results_path `
-mdFile $script:coverage_report_path -xslParams @{
reportTitle = $script:coverage_report_title
}

& "$PSScriptRoot/jacoco-report/embedmissedlines.ps1" -mdFile $script:coverage_report_path
}

function Publish-ToCheckRun {
param(
[string]$reportData
[string]$reportData,
[string]$reportName,
[string]$reportTitle
)

Write-ActionInfo "Publishing Report to GH Workflow"
Expand Down Expand Up @@ -247,12 +290,12 @@ function Publish-ToCheckRun {
Authorization = "token $ghToken"
}
$bdy = @{
name = $report_name
name = $reportName
head_sha = $ref
status = 'completed'
conclusion = 'neutral'
output = @{
title = $report_title
title = $reportTitle
summary = "This run completed at ``$([datetime]::Now)``"
text = $reportData
}
Expand All @@ -262,7 +305,8 @@ function Publish-ToCheckRun {

function Publish-ToGist {
param(
[string]$reportData
[string]$reportData,
[string]$coverageData
)

Write-ActionInfo "Publishing Report to GH Workflow"
Expand All @@ -273,7 +317,7 @@ function Publish-ToGist {

$gistsApiUrl = "https://api.github.com/gists"
$apiHeaders = @{
Accept = "application/vnd.github.v2+json"
Accept = "application/vnd.github.v3+json"
Authorization = "token $gist_token"
}

Expand Down Expand Up @@ -334,6 +378,49 @@ function Publish-ToGist {
$gistFiles."$($reportGistName)_badge.svg" = @{ content = $gistBadgeResult.Content }
}
}
if ($coverageData) {
$gistFiles."$([io.path]::GetFileNameWithoutExtension($reportGistName))_Coverage.md" = @{ content = $coverageData }
}
if ($inputs.coverage_gist_badge_label) {
$coverage_gist_badge_label = $inputs.coverage_gist_badge_label
$coverage_gist_badge_label = Resolve-EscapeTokens $coverage_gist_badge_label $pesterResult -UrlEncode

$coverageXmlData = Select-Xml -Path $coverage_results_path -XPath "/report/counter[@type='LINE']"
$coveredLines = $coverageXmlData.Node.covered
Write-Host "Covered Lines: $coveredLines"
$missedLines = $coverageXmlData.Node.missed
Write-Host "Missed Lines: $missedLines"
if ($missedLines -eq 0) {
$coveragePercentage = 100
} else {
$coveragePercentage = [math]::Round(100 - (($missedLines / $coveredLines) * 100))
}
$coveragePercentageString = "$coveragePercentage%"

if ($coveragePercentage -eq 100) {
$coverage_gist_badge_color = 'brightgreen'
} elseif ($coveragePercentage -ge 80) {
$coverage_gist_badge_color = 'green'
} elseif ($coveragePercentage -ge 60) {
$coverage_gist_badge_color = 'yellowgreen'
} elseif ($coveragePercentage -ge 40) {
$coverage_gist_badge_color = 'yellow'
} elseif ($coveragePercentage -ge 20) {
$coverage_gist_badge_color = 'orange'
} else {
$coverage_gist_badge_color = 'red'
}

$coverage_gist_badge_url = "https://img.shields.io/badge/$coverage_gist_badge_label-$coveragePercentageString-$coverage_gist_badge_color"
Write-ActionInfo "Computed Coverage Badge URL: $coverage_gist_badge_url"
$coverageGistBadgeResult = Invoke-WebRequest $coverage_gist_badge_url -ErrorVariable $coverageGistBadgeError
if ($coverageGistBadgeError) {
$gistFiles."$($reportGistName)_coverage_badge.txt" = @{ content = $coverageGistBadgeError.Message }
}
else {
$gistFiles."$($reportGistName)_coverage_badge.svg" = @{ content = $coverageGistBadgeResult.Content }
}
}

if (-not $reportGist) {
Write-ActionInfo "Creating initial Tests Report Gist"
Expand Down Expand Up @@ -363,11 +450,26 @@ if ($test_results_path) {

$reportData = [System.IO.File]::ReadAllText($test_report_path)

if ($coverage_results_path) {
Set-ActionOutput -Name coverage_results_path -Value $coverage_results_path

Build-CoverageReport

$coverageSummaryData = [System.IO.File]::ReadAllText($coverage_report_path)
}

if ($inputs.skip_check_run -ne $true) {
Publish-ToCheckRun -ReportData $reportData
Publish-ToCheckRun -ReportData $reportData -ReportName $report_name -ReportTitle $report_title
if ($coverage_results_path) {
Publish-ToCheckRun -ReportData $coverageSummaryData -ReportName $coverage_report_name -ReportTitle $coverage_report_title
}
}
if ($inputs.gist_name -and $inputs.gist_token) {
Publish-ToGist -ReportData $reportData
if ($inputs.coverage_gist) {
Publish-ToGist -ReportData $reportData -CoverageData $coverageSummaryData
} else {
Publish-ToGist -ReportData $reportData
}
}
}

Expand Down
39 changes: 39 additions & 0 deletions action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,41 @@ inputs:
You can control which account is used to actually store the state by
generating a token associated with the target account.

coverage_paths:
description: |
Comma-separated list of one or more directories to scan for code
coverage, relative to the root of the project. Will include all .ps1
and .psm1 files under these directories recursively.
required: false

coverage_report_name:
description: |
The name of the code coverage report object that will be attached
to the Workflow Run. Defaults to the name
`COVERAGE_RESULTS_<datetime>` where `<datetime>` is in the form
`yyyyMMdd_hhmmss`.
required: false

coverage_report_title:
description: |
The title of the code coverage report that will be embedded in the
report itself, which defaults to the same as the
`code_coverage_report_name` input.
required: false

coverage_gist:
description: |
If true, will attach the coverage results to the gist specified in
`gist_name`.
required: false

coverage_gist_badge_label:
description: |
If specified, the Test Report Gist will also include an adjacent
badge rendered with the percentage of the associated Coverage Report
and label content of this input.
required: false

tests_fail_step:
description: |
If true, will cause the step to fail if one or more tests fails.
Expand Down Expand Up @@ -181,6 +216,10 @@ outputs:
failed_count:
description: Total number of tests failed.

coverage_results_path:
description: |
Path to the code coverage results file in JaCoCo XML format.


branding:
color: purple
Expand Down
37 changes: 37 additions & 0 deletions jacoco-report/embedmissedlines.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@

[CmdletBinding()]
param(
[Parameter(Mandatory)]
[string]$mdFile
)

$mdData = Get-Content -Path $mdFile

$outputData = @()
foreach ($line in $mdData) {
if ($line -like "- Line #*") {
$linePrefix = $line.Split("|")[0]
$lineNumber = $linePrefix.Split("#")[1]
$arrayLineNumber = $lineNumber - 1

$filePath = $line.Split("|")[1]
if ($IsWindows -or $PSVersionTable.PSVersion.Major -le 5) {
$filePath = $filePath.Replace("/","\")
}
$workspaceFiles = Get-ChildItem -Path "$env:GITHUB_WORKSPACE" -Recurse -File
$resolvedFilePath = $workspaceFiles | Where-Object {$_.FullName -like "*$filePath"}
$fileContents = Get-Content -Path $resolvedFilePath
$missedLine = $fileContents[$arrayLineNumber]

$outputData += $linePrefix
$outputData += "``````"
$outputData += $missedLine
$outputData += "``````"

}
else {
$outputData += $line
}
}

Set-Content -Value $outputData -Path $mdFile
98 changes: 98 additions & 0 deletions jacoco-report/example.jacoco.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@

# Coverage Report: Pester (04/16/2021 11:51:47)

* Pester (04/16/2021 11:51:47)

Outcome: 98.43% Coverage
| Lines Covered: 191
| Lines Missed: 3

## Details:


### src

<details>
<summary>
:x: ChangelogManagement.psm1
</summary>


#### Lines Missed:

- Line #4
```
. $PrivateFile.FullName
```
</details>


### src/public

<details>
<summary>
:heavy_check_mark: Add-ChangelogData.ps1
</summary>


#### All Lines Covered!

</details>



<details>
<summary>
:heavy_check_mark: ConvertFrom-Changelog.ps1
</summary>


#### All Lines Covered!

</details>



<details>
<summary>
:heavy_check_mark: Get-ChangelogData.ps1
</summary>


#### All Lines Covered!

</details>



<details>
<summary>
:heavy_check_mark: New-Changelog.ps1
</summary>


#### All Lines Covered!

</details>



<details>
<summary>
:x: Update-Changelog.ps1
</summary>


#### Lines Missed:

- Line #79
```
throw "You must be running in GitHub Actions to use GitHub LinkMode"
```
- Line #89
```
throw "You must be running in Azure Pipelines to use AzureDevOps LinkMode"
```
</details>


Loading