Pester icon indicating copy to clipboard operation
Pester copied to clipboard

Using ANSI escape codes for output

Open nohwnd opened this issue 4 years ago • 13 comments

Using ANSI escape codes would probably also fix output not being colored in CI, which is very unfortunate:

Travis CI

image

https://travis-ci.org/felixfbecker/PSKubectl/jobs/500233965

VSTS

image

https://felixfbecker.visualstudio.com/PowerGit/_build/results?buildId=179

Originally posted by @felixfbecker in https://github.com/pester/Pester/issues/1265#issuecomment-495924708

nohwnd avatar May 19 '21 12:05 nohwnd

For perf reasons and because of the redirect issue above make sure we use one write host per line (or less).

nohwnd avatar May 19 '21 12:05 nohwnd

Should I look into this?

Thinking that we would extend OutputConfiguration with a new option. If not set, auto-detect.

Would also limit ANSI-output to the same ConsoleColor-values for now as all VT-terminals doesn't support full RGB.

Could maybe introduce a private Write-PesterHost helper function to avoid if ansi/else-blocks in the code. That is unless the syntax gets too complex. Would need something like a [HostMessage[]]-parameter to support multiple vs single write-host calls I guess.

fflaten avatar May 19 '21 15:05 fflaten

if you are interested in this and see some upside then sure why not. Sure add a function to encapsulate the logic, but probably figure it out at the module load/invoke-pester and then reuse the result? Most, if not all, of the output should be contained the Output.ps1

nohwnd avatar May 20 '21 05:05 nohwnd

Other than ANSI, color can be controlled via Azure Devops-specific commands. There are not as many color options available as in Output.ps1 themes though.

https://developercommunity.visualstudio.com/t/write-host-foreground-color-with-powershell-task-i/440605

Travis CI has this unbuffer workaround for colorizing output. https://github.com/travis-ci/travis-ci/issues/7967#issuecomment-424521694

Kieran Marron posted this example of colorizing the Write-Information output. https://blog.kieranties.com/2018/03/26/write-information-with-colours

Getting rid of direct calls to Write-Host by first wrapping it with a new Write-PesterHost or Write-HostOutput or Write-TermOutput call would probably be beneficial to Pester framework flexibility with various CI/CD outputs.

asears avatar May 26 '21 03:05 asears

I'm using my own drop-in replacement for Write-Host to colorize output in CI (Azure DevOps):

I just dot-source it before running anything else and I haven't had any issues yet. Unfortunately it doesn't work with Pester because of the SafeCommands. You might try to embed it, since it would provide an easy way to produce color output. Or at least allow for Write-Host to be overridden, so we can fix it ourselves.

beatcracker avatar Dec 23 '21 22:12 beatcracker

@beatcracker 's suggestions seem great to me, I would love to be able to get colorized output in GitHub Actions and I think that would do the trick.

briantist avatar Apr 18 '22 00:04 briantist

That's the idea. The plan is similar, but tried to also merge multiple messages to a single write-host call so we can fix broken redirection of Information-stream.

Btw Pester 5.3 highlights errors in GitHub Actions. So at least they're red atm. 🙂

fflaten avatar Apr 18 '22 06:04 fflaten

That's the idea. The plan is similar, but tried to also merge multiple messages to a single write-host call so we can fix broken redirection of Information-stream.

Btw Pester 5.3 highlights errors in GitHub Actions. So at least they're red atm. 🙂

Nice, is there a PR or some WIP I can follow?

briantist avatar Apr 18 '22 13:04 briantist

Not yet. Profiled some PoCs when this issue was created, but haven't had time after. Not sure if the stream redirection is worth the perf cost, tried to find the cheapest way.

fflaten avatar Apr 18 '22 15:04 fflaten

Not yet. Profiled some PoCs when this issue was created, but haven't had time after. Not sure if the stream redirection is worth the perf cost, tried to find the cheapest way.

Thanks! A short term change that could be helpful is beatcracker's suggestion of allowing overrides of Write-Host at least. That might not work for every scenario, and that might cause issues with mocking, but it would be something.

briantist avatar Apr 18 '22 15:04 briantist

There's nothing stopping you from overwriting it already. It is unsupported but as long as you use a parameter-compatible replacement it should work fine. The internal SafeCommands-system is mostly there to avoid unintentional hijacks and only used by internal code. Demo:

function global:mywritehost {
    [CmdletBinding()]
    Param(
        [Parameter(ValueFromPipeline=$true)]
        [Alias('Message')]
        [System.Object[]]$Object,
        [System.Object]$Separator,
        [System.ConsoleColor]$ForegroundColor,
        [System.ConsoleColor]$BackgroundColor,
        [switch]$NoNewline
    )

    Microsoft.PowerShell.Utility\Write-Host -Object "AWESOME - $Object" @PSBoundParameters
}

Import-Module Pester

# Overwrite internal Write-Host reference to point at custom function. Will work until re-import of module
& (Get-Module Pester) { $SafeCommands['Write-Host'] = Get-Command -Type Function -Name mywritehost }

# Test it
Invoke-Pester -Path xyz.tests.ps1 -Output Detailed

There won't be any official way of doing this, especially considering the direct use of Write-Host will be replaced when this feature isse is fixed. You could also use -Output None -Passthru and create your own custom output based on the returned result-object (or wait for plugins to be public so you could replace the output-plugin. tracked in #2021).

fflaten avatar Apr 18 '22 19:04 fflaten

function mywritehost {
    [CmdletBinding()]
    Param(
        [Parameter(ValueFromPipeline=$true)]
        [Alias('Message')]
        [System.Object[]]$Object,
        [System.Object]$Separator,
        [System.ConsoleColor]$ForegroundColor,
        [System.ConsoleColor]$BackgroundColor,
        [switch]$NoNewline
    )

    Microsoft.PowerShell.Utility\Write-Host -Object "AWESOME - $Object" @PSBoundParameters
}

Import-Module Pester

& (Get-Module Pester) { param ($c) $SafeCommands['Write-Host'] = $c } (Get-Command mywritehost)

Commenting just because I am stickler for scoping. That function does not have to be global, you can pass the command info in, and assign it. 🙂

nohwnd avatar Apr 22 '22 18:04 nohwnd

Indeed @nohwnd , I did not end up using a global 😆 though in my case I simply dot sourced within the module's runspace. https://github.com/briantist/CcgVault/pull/5/files#diff-99dcb0298ba2b59c1cb805648abc6cd9ac0e8b732fa9dda7a8607b4676343244

briantist avatar Apr 22 '22 22:04 briantist