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

Azure Devops & Github Actions error logging #1996

Merged
merged 26 commits into from
Jun 24, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
c21d55c
Added CIFormat output option
ArmaanMcleod Jun 18, 2021
79ca76a
Merge branch 'main' into azure-devops-error-logging
ArmaanMcleod Jun 18, 2021
1f08feb
Added CI detection
ArmaanMcleod Jun 18, 2021
998de59
Also check Auto is set has been set manually
ArmaanMcleod Jun 19, 2021
e372222
Added Write-CIErrorMessage function to format different CIs
ArmaanMcleod Jun 19, 2021
39d4711
Added CIFormat detection in Output.ps1
ArmaanMcleod Jun 19, 2021
6d180db
Renamed Write-CIErrorMessage to Write-CIErrorToScreen
ArmaanMcleod Jun 19, 2021
b427daa
Remove nullorempty check for header
ArmaanMcleod Jun 19, 2021
c17260f
Updated documentation
ArmaanMcleod Jun 19, 2021
5565dde
Formatting error alignment for github actions
ArmaanMcleod Jun 19, 2021
6331f93
Created Format-CIErrorMessage function to format errors + added tests
ArmaanMcleod Jun 19, 2021
52da432
Write-CIErrorToScreen now just responsible for writing
ArmaanMcleod Jun 19, 2021
6b5caab
Fix formatting
ArmaanMcleod Jun 19, 2021
6feae22
Merge branch 'main' into azure-devops-error-logging
ArmaanMcleod Jun 19, 2021
b905ee6
Adding configuration tests to catch issues
ArmaanMcleod Jun 19, 2021
4b7e439
Set both TF_BUILD and GITHUB_ACTIONS variables in each test to avoid …
ArmaanMcleod Jun 19, 2021
1978fba
Set CIFormat to None for RSpec tests that fail on purpose
ArmaanMcleod Jun 20, 2021
14d211d
Disabling missing Rspec test that fails on purpose
ArmaanMcleod Jun 20, 2021
4f685b2
Removed overriding of CIFormat when env variables don't exist
ArmaanMcleod Jun 20, 2021
c5495e1
Simplified option documentation
ArmaanMcleod Jun 20, 2021
f754c99
Added CI formatting to Main.ps1
ArmaanMcleod Jun 22, 2021
dc46aa0
Simplified Format-CIErrorMessage by putting github actions messages i…
ArmaanMcleod Jun 22, 2021
b8fb16a
Add title to expandable group
ArmaanMcleod Jun 22, 2021
3f37c5c
Fixing up tests and updating docs
ArmaanMcleod Jun 22, 2021
0cee927
Trim GHA message whitespace
ArmaanMcleod Jun 22, 2021
b101e10
Use try/finally when executing tests to ensure previous env variables…
ArmaanMcleod Jun 23, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
32 changes: 31 additions & 1 deletion src/Main.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -899,6 +899,24 @@ function Invoke-Pester {
[PesterConfiguration] $PesterPreference = [PesterConfiguration]::Merge($callerPreference, $Configuration)
}

if ($PesterPreference.Output.CIFormat.Value -eq 'Auto') {
ArmaanMcleod marked this conversation as resolved.
Show resolved Hide resolved

# Variable is set to 'True' if the script is being run by a Azure Devops build task. https://docs.microsoft.com/en-us/azure/devops/pipelines/build/variables?view=azure-devops&tabs=yaml
# Do not fix this to check for boolean value, the value is set to literal string 'True'
if ($env:TF_BUILD -eq 'True') {
$PesterPreference.Output.CIFormat = 'AzureDevops'
}
# Variable is set to 'True' if the script is being run by a Github Actions workflow. https://docs.github.com/en/actions/reference/environment-variables#default-environment-variables
# Do not fix this to check for boolean value, the value is set to literal string 'True'
elseif ($env:GITHUB_ACTIONS -eq 'True') {
$PesterPreference.Output.CIFormat = 'GithubActions'
}

else {
$PesterPreference.Output.CIFormat = 'None'
}
}

& $SafeCommands['Get-Variable'] 'Configuration' -Scope Local | Remove-Variable

# $sessionState = Set-SessionStateHint -PassThru -Hint "Caller - Captured in Invoke-Pester" -SessionState $PSCmdlet.SessionState
Expand Down Expand Up @@ -1161,7 +1179,19 @@ function Invoke-Pester {

}
catch {
Write-ErrorToScreen $_ -Throw:$PesterPreference.Run.Throw.Value -StackTraceVerbosity:$PesterPreference.Output.StackTraceVerbosity.Value
$formatErrorParams = @{
Err = $_
StackTraceVerbosity = $PesterPreference.Output.StackTraceVerbosity.Value
}

if ($PesterPreference.Output.CIFormat.Value -in 'AzureDevops', 'GithubActions') {
$errorMessage = (Format-ErrorMessage @formatErrorParams) -split [Environment]::NewLine
Write-CIErrorToScreen -CIFormat $PesterPreference.Output.CIFormat.Value -Header $errorMessage[0] -Message $errorMessage[1..($errorMessage.Count - 1)]
}
else {
Write-ErrorToScreen @formatErrorParams -Throw:$PesterPreference.Run.Throw.Value
}

if ($PesterPreference.Run.Exit.Value) {
exit -1
}
Expand Down
3 changes: 3 additions & 0 deletions src/Pester.RSpec.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -399,6 +399,9 @@ function New-PesterConfiguration {
StackTraceVerbosity: The verbosity of stacktrace output, options are None, FirstLine, Filtered and Full.
Default value: 'Filtered'

CIFormat: The CI format of error output in build logs, options are None, Auto, AzureDevops and GithubActions.
Default value: 'Auto'

TestDrive:
Enabled: Enable TestDrive.
Default value: $true
Expand Down
19 changes: 19 additions & 0 deletions src/csharp/Pester/OutputConfiguration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ public class OutputConfiguration : ConfigurationSection
{
private StringOption _verbosity;
private StringOption _stackTraceVerbosity;
private StringOption _ciFormat;

public static OutputConfiguration Default { get { return new OutputConfiguration(); } }
public static OutputConfiguration ShallowClone(OutputConfiguration configuration)
Expand All @@ -37,13 +38,15 @@ public OutputConfiguration(IDictionary configuration) : this()
{
Verbosity = configuration.GetObjectOrNull<string>("Verbosity") ?? Verbosity;
StackTraceVerbosity = configuration.GetObjectOrNull<string>("StackTraceVerbosity") ?? StackTraceVerbosity;
CIFormat = configuration.GetObjectOrNull<string>("CIFormat") ?? CIFormat;
}
}

public OutputConfiguration() : base("Output configuration")
{
Verbosity = new StringOption("The verbosity of output, options are None, Normal, Detailed and Diagnostic.", "Normal");
StackTraceVerbosity = new StringOption("The verbosity of stacktrace output, options are None, FirstLine, Filtered and Full.", "Filtered");
CIFormat = new StringOption("The CI format of error output in build logs, options are None, Auto, AzureDevops and GithubActions.", "Auto");
}

public StringOption Verbosity
Expand Down Expand Up @@ -78,6 +81,22 @@ public StringOption StackTraceVerbosity
}
}

public StringOption CIFormat
{
get { return _ciFormat; }
set
{
if (_ciFormat == null)
{
_ciFormat = value;
}
else
{
_ciFormat = new StringOption(_ciFormat, value?.Value);
}
}
}

private string FixMinimal(string value)
{
return string.Equals(value, "Minimal", StringComparison.OrdinalIgnoreCase) ? "Normal" : value;
Expand Down
145 changes: 136 additions & 9 deletions src/functions/Output.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -513,8 +513,21 @@ function Get-WriteScreenPlugin ($Verbosity) {
throw "Container type '$($container.Type)' is not supported."
}

& $SafeCommands["Write-Host"] -ForegroundColor $ReportTheme.Fail "[-] Discovery in $($path) failed with:"
Write-ErrorToScreen $Context.Block.ErrorRecord -StackTraceVerbosity:$PesterPreference.Output.StackTraceVerbosity.Value
$errorHeader = "[-] Discovery in $($path) failed with:"

$formatErrorParams = @{
Err = $Context.Block.ErrorRecord
StackTraceVerbosity = $PesterPreference.Output.StackTraceVerbosity.Value
}

if ($PesterPreference.Output.CIFormat.Value -in 'AzureDevops', 'GithubActions') {
$errorMessage = (Format-ErrorMessage @formatErrorParams) -split [Environment]::NewLine
Write-CIErrorToScreen -CIFormat $PesterPreference.Output.CIFormat.Value -Header $errorHeader -Message $errorMessage
}
else {
& $SafeCommands["Write-Host"] -ForegroundColor $ReportTheme.Fail $errorHeader
Write-ErrorToScreen @formatErrorParams
}
}
}

Expand Down Expand Up @@ -573,8 +586,21 @@ function Get-WriteScreenPlugin ($Verbosity) {
param ($Context)

if ($Context.Result.ErrorRecord.Count -gt 0) {
& $SafeCommands["Write-Host"] -ForegroundColor $ReportTheme.Fail "[-] $($Context.Result.Item) failed with:"
Write-ErrorToScreen $Context.Result.ErrorRecord -StackTraceVerbosity:$PesterPreference.Output.StackTraceVerbosity.Value
$errorHeader = "[-] $($Context.Result.Item) failed with:"

$formatErrorParams = @{
Err = $Context.Result.ErrorRecord
StackTraceVerbosity = $PesterPreference.Output.StackTraceVerbosity.Value
}

if ($PesterPreference.Output.CIFormat.Value -in 'AzureDevops', 'GithubActions') {
$errorMessage = (Format-ErrorMessage @formatErrorParams) -split [Environment]::NewLine
Write-CIErrorToScreen -CIFormat $PesterPreference.Output.CIFormat.Value -Header $errorHeader -Message $errorMessage
}
else {
& $SafeCommands["Write-Host"] -ForegroundColor $ReportTheme.Fail $errorHeader
Write-ErrorToScreen $formatErrorParams
}
}

if ('Normal' -eq $PesterPreference.Output.Verbosity.Value) {
Expand Down Expand Up @@ -640,6 +666,10 @@ function Get-WriteScreenPlugin ($Verbosity) {
throw "Unsupported level of stacktrace output '$($PesterPreference.Output.StackTraceVerbosity.Value)'"
}

if ($PesterPreference.Output.CIFormat.Value -notin 'None', 'Auto', 'AzureDevops', 'GithubActions') {
throw "Unsupported CI format '$($PesterPreference.Output.CIFormat.Value)'"
}

$humanTime = "$(Get-HumanTime ($_test.Duration)) ($(Get-HumanTime $_test.UserDuration)|$(Get-HumanTime $_test.FrameworkDuration))"

if ($PesterPreference.Debug.ShowNavigationMarkers.Value) {
Expand Down Expand Up @@ -671,10 +701,21 @@ function Get-WriteScreenPlugin ($Verbosity) {

}
else {
& $SafeCommands['Write-Host'] -ForegroundColor $ReportTheme.Fail "$margin[-] $out" -NoNewLine
& $SafeCommands['Write-Host'] -ForegroundColor $ReportTheme.FailTime " $humanTime"
$formatErrorParams = @{
Err = $_test.ErrorRecord
ErrorMargin = $error_margin
StackTraceVerbosity = $PesterPreference.Output.StackTraceVerbosity.Value
}

Write-ErrorToScreen $_test.ErrorRecord -ErrorMargin $error_margin -StackTraceVerbosity:$PesterPreference.Output.StackTraceVerbosity.Value
if ($PesterPreference.Output.CIFormat.Value -in 'AzureDevops', 'GithubActions') {
$errorMessage = (Format-ErrorMessage @formatErrorParams) -split [Environment]::NewLine
Write-CIErrorToScreen -CIFormat $PesterPreference.Output.CIFormat.Value -Header "$margin[-] $out $humanTime" -Message $errorMessage
}
else {
& $SafeCommands['Write-Host'] -ForegroundColor $ReportTheme.Fail "$margin[-] $out" -NoNewLine
& $SafeCommands['Write-Host'] -ForegroundColor $ReportTheme.FailTime " $humanTime"
Write-ErrorToScreen @formatErrorParams
}
}
break
}
Expand Down Expand Up @@ -760,8 +801,23 @@ function Get-WriteScreenPlugin ($Verbosity) {
}

foreach ($e in $Context.Block.ErrorRecord) { ConvertTo-FailureLines $e }
& $SafeCommands['Write-Host'] -ForegroundColor $ReportTheme.BlockFail "[-] $($Context.Block.FrameworkData.CommandUsed) $($Context.Block.Path -join ".") failed"
Write-ErrorToScreen $Context.Block.ErrorRecord $error_margin -StackTraceVerbosity:$PesterPreference.Output.StackTraceVerbosity.Value

$errorHeader = "[-] $($Context.Block.FrameworkData.CommandUsed) $($Context.Block.Path -join ".") failed"

$formatErrorParams = @{
Err = $Context.Block.ErrorRecord
ErrorMargin = $error_margin
StackTraceVerbosity = $PesterPreference.Output.StackTraceVerbosity.Value
}

if ($PesterPreference.Output.CIFormat.Value -in 'AzureDevops', 'GithubActions') {
$errorMessage = (Format-ErrorMessage @formatErrorParams) -split [Environment]::NewLine
Write-CIErrorToScreen -CIFormat $PesterPreference.Output.CIFormat.Value -Header $errorHeader -Message $errorMessage
}
else {
& $SafeCommands['Write-Host'] -ForegroundColor $ReportTheme.BlockFail $errorHeader
Write-ErrorToScreen @formatErrorParams
}
}

$p.End = {
Expand All @@ -773,6 +829,77 @@ function Get-WriteScreenPlugin ($Verbosity) {
New-PluginObject @p
}

function Format-CIErrorMessage {
[OutputType([System.Collections.Generic.List[string]])]
[CmdletBinding()]
param (
[Parameter(Mandatory)]
[ValidateSet('AzureDevops', 'GithubActions', IgnoreCase)]
[string] $CIFormat,

[Parameter(Mandatory)]
[string] $Header,

[Parameter(Mandatory)]
[string[]] $Message
)

$lines = [System.Collections.Generic.List[string]]@()

if ($CIFormat -eq 'AzureDevops') {

# header task issue error, so it gets reported to build log
# https://docs.microsoft.com/en-us/azure/devops/pipelines/scripts/logging-commands?view=azure-devops&tabs=powershell#example-log-an-error
$headerTaskIssueError = "##vso[task.logissue type=error] $Header"
$lines.Add($headerTaskIssueError)

# Add subsequent messages as errors, but do not get reported to build log
foreach ($line in $Message) {
$lines.Add("##[error] $line")
}
}
elseif ($CIFormat -eq 'GithubActions') {

# header error, so it gets reported to build log
# https://docs.github.com/en/actions/reference/workflow-commands-for-github-actions#setting-an-error-message
$headerError = "::error::$($Header.TrimStart())"
$lines.Add($headerError)

# Add rest of messages inside expandable group
# https://docs.github.com/en/actions/reference/workflow-commands-for-github-actions#grouping-log-lines
$lines.Add("::group::Message")

foreach ($line in $Message) {
$lines.Add($line.TrimStart())
}

$lines.Add("::endgroup::")
}

return $lines
}

function Write-CIErrorToScreen {
[CmdletBinding()]
param (
[Parameter(Mandatory)]
[ValidateSet('AzureDevops', 'GithubActions', IgnoreCase)]
[string] $CIFormat,

[Parameter(Mandatory)]
[string] $Header,

[Parameter(Mandatory)]
[string[]] $Message
)

$errorMessage = Format-CIErrorMessage @PSBoundParameters

foreach ($line in $errorMessage) {
& $SafeCommands['Write-Host'] $line
}
}

function Format-ErrorMessage {
[CmdletBinding()]
param (
Expand Down
20 changes: 17 additions & 3 deletions tst/Pester.Mock.RSpec.ts.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -342,8 +342,16 @@ i -PassThru:$PassThru {
}

$r = Invoke-Pester -Configuration ([PesterConfiguration]@{
Run = @{ ScriptBlock = $sb; PassThru = $true }
Should = @{ ErrorAction = 'Continue' }
Run = @{
ScriptBlock = $sb
PassThru = $true
}
Should = @{
ErrorAction = 'Continue'
}
Output = @{
CIFormat = 'None'
}
})

$t = $r.Containers[0].Blocks[0].Tests[0]
Expand Down Expand Up @@ -1011,7 +1019,13 @@ i -PassThru:$PassThru {
}

$r = Invoke-Pester -Configuration ([PesterConfiguration]@{
Run = @{ ScriptBlock = $sb; PassThru = $true }
Run = @{
ScriptBlock = $sb
PassThru = $true
}
Output = @{
CIFormat = 'None'
}
})

$t = $r.Containers[0].Blocks[0].Tests[0]
Expand Down